package com.signin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.signin.model.dto.SignInSessionDTO;
import com.signin.model.dto.StudentSignInDTO;
import com.signin.model.entity.SignInRecord;
import com.signin.model.entity.SignInSession;
import com.signin.repository.SignInRecordRepository;
import com.signin.repository.SignInSessionRepository;
import com.signin.service.SignInService;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

@Service
public class SignInServiceImpl implements SignInService {

    @Autowired
    private SignInSessionRepository sessionRepository;

    @Autowired
    private SignInRecordRepository recordRepository;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    @Transactional
    public SignInSessionDTO createSignInSession(SignInSessionDTO sessionDTO) {
        // 检查是否已有同一教室的进行中签到
        SignInSession activeSession = sessionRepository.selectOne(new QueryWrapper<SignInSession>()
                .eq("status", 1)
                .eq("classroom", sessionDTO.getClassroom()));
        if (activeSession != null) {
            throw new RuntimeException("该教室已有进行中的签到会话，请先结束之前的签到");
        }

        SignInSession session = new SignInSession();
        BeanUtils.copyProperties(sessionDTO, session);
        session.setStatus(0); // 初始状态为未开始
        session.setCreateTime(new Date());
        // 如果DTO中没有设置日期，则默认为当前日期
        if (session.getDate() == null) {
            session.setDate(new Date());
        }
        sessionRepository.insert(session);

        // 缓存到Redis，设置过期时间为24小时
        redisTemplate.opsForValue().set("active_session", session.getId(), 24, TimeUnit.HOURS);

        BeanUtils.copyProperties(session, sessionDTO);
        return sessionDTO;
    }

    @Override
    @Transactional
    public boolean startSignIn(Long sessionId) {
        SignInSession session = sessionRepository.selectById(sessionId);
        if (session == null) {
            return false;
        }

        // 更新状态为进行中，并记录开始时间
        // 允许从未开始(0)或已结束(2)状态重新开始签到
        session.setStatus(1);
        session.setStartTime(new Date());
        // 清除结束时间，因为签到重新开始了
        session.setEndTime(null);
        int count = sessionRepository.updateById(session);

        return count > 0;
    }

    @Override
    @Transactional
    public boolean endSignIn(Long sessionId) {
        SignInSession session = sessionRepository.selectById(sessionId);
        if (session == null || session.getStatus() != 1) {
            return false;
        }

        // 更新状态为已结束，并记录结束时间
        session.setStatus(2);
        session.setEndTime(new Date());
        int count = sessionRepository.updateById(session);

        // 不再需要清除Redis缓存，因为不再使用Redis存储单个活动会话
        
        return count > 0;
    }

    @Override
    @Transactional
    public boolean studentSignIn(Long sessionId, StudentSignInDTO signInDTO) {
        // 检查签到会话状态
        SignInSession session = sessionRepository.selectById(sessionId);
        if (session == null || session.getStatus() != 1) {
            return false;
        }

        // 检查学生选择的教室是否与签到会话的教室匹配
        if (!signInDTO.getClassroomLocation().equals(session.getClassroom())) {
            return false;
        }

        // 检查是否已经签到过
        SignInRecord existingRecord = recordRepository.selectOne(new QueryWrapper<SignInRecord>()
                .eq("session_id", sessionId)
                .eq("student_name", signInDTO.getStudentName()));
        if (existingRecord != null) {
            return false;
        }

        // 创建签到记录
        SignInRecord record = new SignInRecord();
        record.setSessionId(sessionId);
        record.setStudentName(signInDTO.getStudentName());
        record.setClassroomLocation(signInDTO.getClassroomLocation());
        record.setSignInTime(new Date());
        int count = recordRepository.insert(record);

        return count > 0;
    }

    @Override
    public SignInSessionDTO getSignInSession(Long sessionId) {
        SignInSession session = sessionRepository.selectById(sessionId);
        if (session == null) {
            return null;
        }

        SignInSessionDTO sessionDTO = new SignInSessionDTO();
        BeanUtils.copyProperties(session, sessionDTO);
        return sessionDTO;
    }

    @Override
    public List<SignInRecord> getSignInRecords(Long sessionId) {
        return recordRepository.selectList(new QueryWrapper<SignInRecord>()
                .eq("session_id", sessionId)
                .orderByDesc("sign_in_time"));
    }

    @Override
    public byte[] exportSignInData(Long sessionId) {
        // 获取签到会话信息
        SignInSession session = sessionRepository.selectById(sessionId);
        if (session == null) {
            throw new RuntimeException("签到会话不存在");
        }

        // 获取签到记录
        List<SignInRecord> records = getSignInRecords(sessionId);

        // 创建Excel文件
        try (Workbook workbook = new XSSFWorkbook();
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

            Sheet sheet = workbook.createSheet("签到记录");

            // 创建表头
            Row headerRow = sheet.createRow(0);
            String[] headers = {"日期", "班级", "节次", "课题", "教师姓名", "学生姓名", "教室位置", "签到时间"};
            for (int i = 0; i < headers.length; i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
            }

            // 填充数据
            for (int i = 0; i < records.size(); i++) {
                SignInRecord record = records.get(i);
                Row row = sheet.createRow(i + 1);

                row.createCell(0).setCellValue(session.getDate().toString());
                row.createCell(1).setCellValue(session.getClassName());
                row.createCell(2).setCellValue(session.getSectionNumber());
                row.createCell(3).setCellValue(session.getTopic());
                row.createCell(4).setCellValue(session.getTeacherName());
                row.createCell(5).setCellValue(record.getStudentName());
                row.createCell(6).setCellValue(record.getClassroomLocation());
                row.createCell(7).setCellValue(record.getSignInTime().toString());
            }

            workbook.write(outputStream);
            return outputStream.toByteArray();

        } catch (IOException e) {
            throw new RuntimeException("导出Excel失败", e);
        }
    }

    @Override
    public SignInSessionDTO getCurrentActiveSession() {
        // 直接从数据库查询所有进行中的签到会话
        // 由于现在允许多个教室同时签到，不再使用Redis缓存单个活动会话
        SignInSession session = sessionRepository.selectOne(new QueryWrapper<SignInSession>()
                .eq("status", 1)
                .orderByDesc("create_time")
                .last("LIMIT 1"));
        if (session == null) {
            return null;
        }

        SignInSessionDTO sessionDTO = new SignInSessionDTO();
        BeanUtils.copyProperties(session, sessionDTO);
        return sessionDTO;
    }
    
    @Override
    public SignInSessionDTO getCurrentActiveSessionByClassroom(String classroom) {
        // 首先尝试查询指定教室的进行中签到会话
        SignInSession session = sessionRepository.selectOne(new QueryWrapper<SignInSession>()
                .eq("status", 1)
                .eq("classroom", classroom)
                .orderByDesc("create_time")
                .last("LIMIT 1"));
        
        // 如果没有进行中会话，查询该教室最新创建的会话（即使已结束）
        if (session == null) {
            session = sessionRepository.selectOne(new QueryWrapper<SignInSession>()
                    .eq("classroom", classroom)
                    .orderByDesc("create_time")
                    .last("LIMIT 1"));
        }
        
        if (session == null) {
            return null;
        }

        SignInSessionDTO sessionDTO = new SignInSessionDTO();
        BeanUtils.copyProperties(session, sessionDTO);
        return sessionDTO;
    }
    
    @Override
    public Map<String, Object> queryHistoricalSessions(String classroom, Date startDate, Date endDate, int page, int pageSize) {
        // 计算偏移量
        int offset = (page - 1) * pageSize;
        
        // 创建查询条件
        QueryWrapper<SignInSession> queryWrapper = createHistoricalSessionsQueryWrapper(classroom, startDate, endDate);
        
        // 查询总数（不使用分页）
        long total = (long) sessionRepository.selectList(queryWrapper).size();
        
        // 应用分页
        queryWrapper.last("LIMIT " + pageSize + " OFFSET " + offset);
        
        // 查询数据
        List<SignInSession> sessions = sessionRepository.selectList(queryWrapper);
        
        // 转换数据格式
        List<Map<String, Object>> data = convertSessionsToResponseFormat(sessions);
        
        // 返回分页结果
        Map<String, Object> result = new HashMap<>();
        result.put("data", data);
        result.put("total", total);
        result.put("page", page);
        result.put("pageSize", pageSize);
        
        return result;
    }
    
    @Override
    public List<Map<String, Object>> queryHistoricalSessions(String classroom, Date startDate, Date endDate) {
        // 创建查询条件
        QueryWrapper<SignInSession> queryWrapper = createHistoricalSessionsQueryWrapper(classroom, startDate, endDate);
        
        // 查询所有符合条件的数据
        List<SignInSession> sessions = sessionRepository.selectList(queryWrapper);
        
        // 转换为前端需要的格式
        return convertSessionsToResponseFormat(sessions);
    }
    
    // 创建历史会话查询条件
    private QueryWrapper<SignInSession> createHistoricalSessionsQueryWrapper(String classroom, Date startDate, Date endDate) {
        QueryWrapper<SignInSession> queryWrapper = new QueryWrapper<>();
        
        // 如果指定了教室，添加教室条件
        if (classroom != null && !classroom.isEmpty()) {
            queryWrapper.eq("classroom", classroom);
        }
        
        // 如果指定了开始日期，添加开始日期条件
        if (startDate != null) {
            queryWrapper.ge("date", startDate);
        }
        
        // 如果指定了结束日期，添加结束日期条件
        if (endDate != null) {
            queryWrapper.le("date", endDate);
        }
        
        // 按日期倒序排列，最新的在前
        queryWrapper.orderByDesc("date", "create_time");
        
        return queryWrapper;
    }
    
    // 将会话列表转换为响应格式
    private List<Map<String, Object>> convertSessionsToResponseFormat(List<SignInSession> sessions) {
        return sessions.stream().map(session -> {
            Map<String, Object> result = new java.util.HashMap<>();
            result.put("id", session.getId());
            result.put("className", session.getClassName());
            result.put("sectionNumber", session.getSectionNumber());
            result.put("topic", session.getTopic());
            result.put("teacherName", session.getTeacherName());
            result.put("classroom", session.getClassroom());
            result.put("date", session.getDate());
            result.put("createTime", session.getCreateTime());
            result.put("startTime", session.getStartTime());
            result.put("endTime", session.getEndTime());
            result.put("status", session.getStatus());
            
            // 统计签到人数
            Long recordCount = recordRepository.selectCount(new QueryWrapper<SignInRecord>()
                    .eq("session_id", session.getId()));
            result.put("recordCount", recordCount);
            
            return result;
        }).collect(java.util.stream.Collectors.toList());
    }
    
    @Override
    @Transactional
    public boolean kickOutStudent(Long sessionId, String studentName) {
        // 检查签到会话是否存在且状态为进行中
        SignInSession session = sessionRepository.selectById(sessionId);
        if (session == null || session.getStatus() != 1) {
            return false;
        }
        
        // 删除指定学生的签到记录
        int count = recordRepository.delete(new QueryWrapper<SignInRecord>()
                .eq("session_id", sessionId)
                .eq("student_name", studentName));
        
        return count > 0;
    }
    
    @Override
    @Transactional
    public Map<String, Object> importSignInData(InputStream inputStream) {
        Map<String, Object> result = new HashMap<>();
        int totalRows = 0;
        int successRows = 0;
        int failedRows = 0;
        StringBuilder errorMessage = new StringBuilder();
        
        try (Workbook workbook = new XSSFWorkbook(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0);
            if (sheet == null) {
                throw new RuntimeException("Excel文件中没有工作表");
            }
            
            // 记录已处理的会话信息，防止重复创建
            Map<String, SignInSession> sessionMap = new HashMap<>();
            
            // 跳过表头，从第二行开始处理数据
            for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
                totalRows++;
                Row row = sheet.getRow(rowNum);
                if (row == null) continue;
                
                try {
                    // 读取数据：日期、节次、班级、学生姓名、课题、教师姓名、教室位置
                    String dateStr = getCellValue(row.getCell(0));
                    String sectionNumber = getCellValue(row.getCell(1));
                    String className = getCellValue(row.getCell(2));
                    String studentName = getCellValue(row.getCell(3));
                    String topic = getCellValue(row.getCell(4));
                    String teacherName = getCellValue(row.getCell(5));
                    String classroom = getCellValue(row.getCell(6));
                    
                    // 验证必要字段
                    if (dateStr == null || sectionNumber == null || className == null || 
                        studentName == null || teacherName == null || classroom == null) {
                        failedRows++;
                        errorMessage.append("第").append(rowNum + 1).append("行：缺少必要字段\n");
                        continue;
                    }
                    
                    // 解析日期
                    Date date = parseDate(dateStr);
                    
                    // 生成会话唯一标识：日期+班级+节次+教师
                    String sessionKey = dateStr + "_" + className + "_" + sectionNumber + "_" + teacherName;
                    
                    // 获取或创建签到会话
                    SignInSession session = sessionMap.get(sessionKey);
                    if (session == null) {
                        // 检查是否已存在相同会话
                        QueryWrapper<SignInSession> sessionWrapper = new QueryWrapper<>();
                        sessionWrapper.eq("date", date)
                                     .eq("class_name", className)
                                     .eq("section_number", sectionNumber)
                                     .eq("teacher_name", teacherName);
                        session = sessionRepository.selectOne(sessionWrapper);
                        
                        if (session == null) {
                            // 创建新会话
                            session = new SignInSession();
                            session.setDate(date);
                            // 解析节次，支持多种格式：纯数字、"第1节"、"第一节课"等
                            try {
                                int sectionNum = parseSectionNumber(sectionNumber);
                                session.setSectionNumber(sectionNum);
                            } catch (Exception e) {
                                throw new RuntimeException("节次格式不正确：" + sectionNumber + "，请使用数字或'第X节'格式");
                            }
                            session.setClassName(className);
                            session.setTopic(topic);
                            session.setTeacherName(teacherName);
                            session.setClassroom(classroom);
                            session.setStatus(2); // 设置为已结束状态
                            session.setCreateTime(new Date());
                            session.setStartTime(new Date()); // 导入时设置创建时间为开始时间
                            session.setEndTime(new Date()); // 导入时设置结束时间
                            sessionRepository.insert(session);
                        }
                        
                        sessionMap.put(sessionKey, session);
                    }
                    
                    // 检查学生是否已经签到
                    QueryWrapper<SignInRecord> recordWrapper = new QueryWrapper<>();
                    recordWrapper.eq("session_id", session.getId())
                                 .eq("student_name", studentName);
                    SignInRecord existingRecord = recordRepository.selectOne(recordWrapper);
                    
                    if (existingRecord == null) {
                        // 创建签到记录
                        SignInRecord record = new SignInRecord();
                        record.setSessionId(session.getId());
                        record.setStudentName(studentName);
                        record.setClassroomLocation(classroom);
                        record.setSignInTime(new Date()); // 导入时设置当前时间为签到时间
                        recordRepository.insert(record);
                    }
                    
                    successRows++;
                } catch (Exception e) {
                    failedRows++;
                    errorMessage.append("第").append(rowNum + 1).append("行：").append(e.getMessage()).append("\n");
                }
            }
            
            result.put("totalRows", totalRows);
            result.put("successRows", successRows);
            result.put("failedRows", failedRows);
            result.put("errorMessage", errorMessage.toString());
            result.put("success", true);
            
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "导入失败：" + e.getMessage());
        }
        
        return result;
    }
    
    /**
     * 解析节次数据，支持多种格式
     * @param sectionStr 节次字符串
     * @return 节次数字
     */
    private int parseSectionNumber(String sectionStr) {
        if (sectionStr == null || sectionStr.trim().isEmpty()) {
            throw new RuntimeException("节次不能为空");
        }
        
        // 去除空格
        String trimmed = sectionStr.trim();
        
        // 尝试直接解析数字
        if (trimmed.matches("\\d+")) {
            return Integer.parseInt(trimmed);
        }
        
        // 处理"第X节"、"第X节课"格式
        Pattern sectionPattern = Pattern.compile("第(\\d+)节\\w*");
        Matcher matcher = sectionPattern.matcher(trimmed);
        if (matcher.find()) {
            return Integer.parseInt(matcher.group(1));
        }
        
        // 处理"X节课"格式
        Pattern classPattern = Pattern.compile("(\\d+)节课?");
        matcher = classPattern.matcher(trimmed);
        if (matcher.find()) {
            return Integer.parseInt(matcher.group(1));
        }
        
        // 如果都不匹配，抛出异常
        throw new RuntimeException("无法识别的节次格式");
    }
    
    // 辅助方法：获取单元格的值
    private String getCellValue(Cell cell) {
        if (cell == null) return null;
        
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();
            case NUMERIC:
                // 处理日期格式的数字
                if (DateUtil.isCellDateFormatted(cell)) {
                    return new SimpleDateFormat("yyyy/MM/dd").format(cell.getDateCellValue());
                } else {
                    // 处理普通数字，去除小数点和末尾的0
                double numericValue = cell.getNumericCellValue();
                if (numericValue == Math.floor(numericValue)) {
                    // 如果是整数，返回整数格式的字符串
                    return String.valueOf((int)numericValue).trim();
                } else {
                    // 如果是小数，返回原始格式
                    return String.valueOf(numericValue).trim();
                }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return cell.getStringCellValue().trim();
                } catch (Exception e) {
                    return null;
                }
            default:
                return null;
        }
    }
    
    // 辅助方法：解析日期字符串
    private Date parseDate(String dateStr) throws Exception {
        if (dateStr == null) return new Date();
        
        // 支持多种日期格式
        String[] formats = {"yyyy/MM/dd", "yyyy-MM-dd", "yyyy年MM月dd日", "yyyy.MM.dd"};
        
        for (String format : formats) {
            try {
                return new SimpleDateFormat(format).parse(dateStr);
            } catch (Exception ignored) {
            }
        }
        
        // 如果都解析失败，尝试将其作为时间戳解析
        try {
            return new Date(Long.parseLong(dateStr));
        } catch (Exception e) {
            throw new RuntimeException("日期格式不正确：" + dateStr);
        }
    }
    
    @Override
    public byte[] exportHistoricalData(Map<String, Object> params) {
        // 解析参数
        String classroom = (String) params.get("classroom");
        Date startDate = null;
        Date endDate = null;
        
        // 处理日期范围参数
        if (params.containsKey("startDate")) {
            Object startDateObj = params.get("startDate");
            if (startDateObj != null) {
                if (startDateObj instanceof Date) {
                    startDate = (Date) startDateObj;
                } else {
                    // 处理字符串格式的日期
                    try {
                        startDate = new Date(Long.parseLong(startDateObj.toString()));
                    } catch (Exception e) {
                        // 忽略转换异常，使用null
                    }
                }
            }
        }
        
        if (params.containsKey("endDate")) {
            Object endDateObj = params.get("endDate");
            if (endDateObj != null) {
                if (endDateObj instanceof Date) {
                    endDate = (Date) endDateObj;
                } else {
                    // 处理字符串格式的日期
                    try {
                        endDate = new Date(Long.parseLong(endDateObj.toString()));
                    } catch (Exception e) {
                        // 忽略转换异常，使用null
                    }
                }
            }
        }
        
        // 创建Excel文件
        try (Workbook workbook = new XSSFWorkbook();
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

            Sheet sheet = workbook.createSheet("历史签到记录");

            // 创建表头 - 按照需求的字段顺序
            Row headerRow = sheet.createRow(0);
            String[] headers = {"日期", "节次", "班级", "学生姓名", "课题", "教师姓名", "教室位置"};
            for (int i = 0; i < headers.length; i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
            }
            
            // 查询符合条件的所有会话
            QueryWrapper<SignInSession> queryWrapper = new QueryWrapper<>();
            
            // 如果指定了教室，添加教室条件
            if (classroom != null && !classroom.isEmpty()) {
                queryWrapper.eq("classroom", classroom);
            }
            
            // 如果指定了开始日期，添加开始日期条件
            if (startDate != null) {
                queryWrapper.ge("date", startDate);
            }
            
            // 如果指定了结束日期，添加结束日期条件
            if (endDate != null) {
                queryWrapper.le("date", endDate);
            }
            
            // 按日期倒序排列
            queryWrapper.orderByDesc("date", "create_time");
            
            List<SignInSession> sessions = sessionRepository.selectList(queryWrapper);
            
            int rowIndex = 1;
            
            // 遍历所有会话，获取每个会话的签到记录
            for (SignInSession session : sessions) {
                List<SignInRecord> records = recordRepository.selectList(new QueryWrapper<SignInRecord>()
                        .eq("session_id", session.getId())
                        .orderByDesc("sign_in_time"));
                
                // 如果会话没有签到记录，跳过
                if (records.isEmpty()) {
                    continue;
                }
                
                // 为每个签到记录创建一行
                for (SignInRecord record : records) {
                    Row row = sheet.createRow(rowIndex++);
                    
                    // 按需求的字段顺序填充数据，使用SimpleDateFormat格式化日期为"YYYY年MM月DD日"格式
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
                    row.createCell(0).setCellValue(dateFormat.format(session.getDate()));
                    row.createCell(1).setCellValue(session.getSectionNumber());
                    row.createCell(2).setCellValue(session.getClassName());
                    row.createCell(3).setCellValue(record.getStudentName());
                    row.createCell(4).setCellValue(session.getTopic());
                    row.createCell(5).setCellValue(session.getTeacherName());
                    row.createCell(6).setCellValue(session.getClassroom());
                }
            }
            
            // 自动调整列宽
            for (int i = 0; i < headers.length; i++) {
                sheet.autoSizeColumn(i);
            }
            
            workbook.write(outputStream);
            return outputStream.toByteArray();

        } catch (IOException e) {
            throw new RuntimeException("导出Excel失败", e);
        }
    }
}